#include "camera_video_enc_imp.h"
#include "hal_stream_convert.h"
#include "base_log.h"
#include "base_file_util.h"
#include <map>
#include <mutex>

namespace El {
namespace Hal {

ICameraVideoEnc &ICameraVideoEnc::GetInstance(uint32_t channel, uint32_t stream)
{
    static std::map<std::pair<uint32_t, uint32_t>, CameraVideoEnc *> instances;
    static std::mutex mutex;

    std::lock_guard<std::mutex> lock(mutex);
    auto key = std::make_pair(channel, stream);
    auto it = instances.find(key);
    if (it == instances.end()) {
        CameraVideoEnc *instance = new CameraVideoEnc(channel, stream);
        instances.emplace(key, instance);
        return *instance;
    }
    return *it->second;
}

CameraVideoEnc::CameraVideoEnc(uint32_t channel, uint32_t stream) : channel_(channel), stream_(stream) {}

int32_t CameraVideoEnc::Start(PacketCallback cb)
{
    int32_t handle = 0;
    if (stream_ == MEDIA_VIDEO_ENC_STREAM_SNAPSHOT || stream_ == MEDIA_VIDEO_ENC_STREAM_SMALL_SNAPSHOT) {
        handle = cb_list_.Register(cb);
        if (handle < 0) {
            LOG_ERROR("Failed to register callback");
            return -1;
        }
    } else {
        handle = StreamConverter ::GetInstance().RegisterVideoCallback(
            [this, cb](const VideoEncPacket &frame) { cb(frame); });
    }
    return handle;
}

void CameraVideoEnc::Stop(int32_t handle)
{
    if (stream_ != MEDIA_VIDEO_ENC_STREAM_SNAPSHOT) {
        StreamConverter::GetInstance().RegisterVideoCallback(nullptr);
    } else {
        cb_list_.Unregister(handle);
    }
}

bool CameraVideoEnc::ForceIFrame()
{
    return true;
}

bool CameraVideoEnc::Snapshot()
{
    // 获取当前目录下的图片
    std::string path;
    if (stream_ == MEDIA_VIDEO_ENC_STREAM_SNAPSHOT) {
        path = "../resource/1080p.jpg";
    } else {
        path = "../resource/720p.jpg";
    }
    std::vector<uint8_t> buffer;
    if (!Base::LoadBufferFromFile(path, buffer)) {
        LOG_ERROR("Failed to load snapshot file: %s", path.c_str());
        return false;
    }

    // 将buffer中的数据转换为VideoEncPacket
    VideoEncPacket packet;
    packet.buf = reinterpret_cast<uint8_t *>(buffer.data());
    packet.len = static_cast<uint32_t>(buffer.size());
    packet.pts =
        std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch())
            .count();
    packet.seq = 0;                      // 可以设置为适当的序列号
    packet.frameType = MEDIA_FRAME_JPEG; // JPEG图片是I帧
    packet.utc = packet.pts;             // 使用相同的时间戳作为UTC时间
    if (stream_ == MEDIA_VIDEO_ENC_STREAM_SNAPSHOT) {
        packet.width = 1920;  // 需要设置实际的宽度
        packet.height = 1080; // 需要设置实际的高度
    } else {
        packet.width = 1280; // 需要设置实际的宽度
        packet.height = 720; // 需要设置实际的高度
    }
    packet.fps = 0; // 对于快照，帧率可以设为0
    packet.packType = MEDIA_VIDEO_ENC_PACK_ES;
    packet.codecType = MEDIA_VIDEO_CODEC_UNKOWN;

    // 调用回调函数发送数据
    cb_list_.InvokeAll(packet);

    return true;
}

bool CameraVideoEnc::GetEncFormat(VideoEncFormat &enc)
{
    return El::Hal::StreamConverter::GetInstance().GetVideoInfo(enc);
}

void CameraVideoEnc::SetOSD(bool enable)
{
    (void)enable;
}

} // namespace Hal
} // namespace El